我试图在Python脚本中进行产品版本控制有一个特定的原因,但我无法弄清楚如何以优雅的方式做到这一点 - 请帮忙。
目前我正在做类似下面的事情。但是,在更改版本内容时,脚本很难维护。
class Product(object):
def __init__(client):
self.version = client.version # get client version from another module
def function():
if self.version == '1.0':
print('for version 1.0')
elif self.version == '2.0':
print('for version 2.0')
else:
print(f'function not support {self.version}')
因此,我想做类似下面的事情来分离具有相同名称的功能。
class Product(object):
def __init__(client):
self.version = client.version # get client version from another module
def function():
print('for version 1.0')
def function():
print('for version 2.0')
我正在考虑使用装饰器来实现这个目的:
class Product(object):
def __init__(client):
self.version = client.version # get client version from another module
@version(1.0)
def function():
print('for version 1.0')
@version(2.0)
def function():
print('for version 2.0')
但是,我没弄明白怎么样......看起来装饰师不能做这种操作或者我只是不明白怎么做。
有没有优雅的方法来做到这一点?
继承可能是执行此操作的最佳方式,但由于您专门询问了装饰器,我想告诉您可以使用装饰器执行此操作。
您需要使用字典按版本存储函数,然后查找在运行时使用的版本。这是一个例子。
version_store = {}
def version(v):
def dec(f):
name = f.__qualname__
version_store[(name, v)] = f
def method(self, *args, **kwargs):
f = version_store[(name, self.version)]
return f(self, *args, **kwargs)
return method
return dec
class Product(object):
def __init__(self, version):
self.version = version
@version("1.0")
def function(self):
print("1.0")
@version("2.0")
def function(self):
print("2.0")
Product("1.0").function()
Product("2.0").function()
你能把你的Product
类放到两个模块v1和v2中,然后有条件地导入它们吗?
例如:
Productv1.py
class Product(object):
def function():
print('for version 1.0')
Productv2.py
class Product(object):
def function():
print('for version 2.0')
然后在你的主文件中:
main.py
if client.version == '1.0':
from Productv1 import Product
elif client.version == '2.0':
from Productv2 import Product
else:
print(f'function not support {self.version}')
p = Product
p.function()
作为另一种选择,你可以去一些工厂创建你的课程。
创建版本化函数(请注意self
参数)。这可以在不同的模块中完成。另外,添加一些集合以根据版本号获取函数。
def func_10(self):
print('for version 1.0')
def func_20(self):
print('for version 2.0')
funcs = {"1.0": func_10,
"2.0": func_20}
添加包含实现的静态部分的基类和实用程序类,以在以下位置创建实例:
class Product:
def __init__(self, version):
self.version = version
class ProductFactory(type):
@classmethod
def get_product_class(mcs, version):
# this will return an instance right away, due to the (version) in the end
return type.__new__(mcs, "Product_{}".format(version.replace(".","")), (Product,), {"function": funcs.get(version)})(version)
# if you want to return a class object to instantiate in your code omit the (version) in the end
使用这个:
p1 = ProductFactory.get_product_class("1.0")
p2 = ProductFactory.get_product_class("2.0")
print(p1.__class__.__name__) # Product_10
p1.function() # for version 1.0
print(p1.function) # <bound method func_10 of <__main__.Product_10 object at 0x0000000002A157F0>>
print(p2.__class__.__name__) # Product_20
p2.function() # for version 2.0
print(p2.function) # <bound method func_20 of <__main__.Product_20 object at 0x0000000002A15860>>
一般来说,不要。 Method overloading在Python中不鼓励。如果您必须在课程级别上进行区分,请阅读@ Loocid的答案。我不会重复他的优秀职位。
如果你想要一个方法级别,因为差异足够小,尝试这样的事情:
class Product:
def method(self):
if self.version == "1.0":
return self._methodv1()
elif self.version == "2.0":
return self._methodv2()
else:
raise ValueError("No appropriate method for version {}".format(self.version))
def _methodv1(self):
# implementation
def _methodv2(self):
# implementation
请注意:
要么:
class Product:
def method_old(self):
# transform arguments to v2 method:
return self.method()
def method(self):
# implementation
我得到的氛围我的第一种方法更适合你手头的问题,但我想把第二种方法包括在后代中。如果您在10年后编辑代码,那将使您更快乐。如果明天使用当前代码编辑代码,第一种方法会让你更快乐。
我不是一个python开发人员,但我不禁想知道你为什么不做这样的事情:
class Product(object):
def __init__(self, version):
self.version = version
def function(self):
print('for version ' + self.version)
或者你可以做,dict.get
调用函数,并在print
做lambda
,如果没有什么是正确的:
def func_1(self):
print('for version 1.0')
def func_2(self):
print('for version 2.0')
def function(self):
funcs = {"1.0": self.func_1,
"2.0": self.func_2}
funcs.get(self.version,lambda: print(f'function not support {self.version}'))()
例:
class Product(object):
def __init__(self,version):
self.version = version
def func_1(self):
print('for version 1.0')
def func_2(self):
print('for version 2.0')
def function(self):
funcs = {"1.0": self.func_1,
"2.0": self.func_2}
funcs.get(self.version,lambda: print(f'function not support {self.version}'))()
Product('1.0').function()
Product('2.0').function()
Product('3.0').function()
输出:
for version 1.0
for version 2.0
function not support 3.0
你可以使用装饰器
def v_decorate(func):
def func_wrapper(name):
return func(name)
return func_wrapper
和
@v_decorate
def get_version(name):
return "for version {0} ".format(name)
你可以打电话给它
get_version(1.0)
'for version 1.0 '
get_version(2.0)
'for version 2.0 '