特定の理由で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')
これを達成するためにdecoratorを使用することを考えていました:
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
クラスを2つのモジュール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>>
一般的にはしないでください。メソッドのオーバーロード は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
私の最初の方法はあなたの問題にもっと適していると思いますが、後世のために2番目の方法を含めたいと思いました。 10年後のコードを編集すれば、それがあなたを幸せにします。明日現在のコードを使用してコードを編集する場合、最初の方法はあなたを幸せにします。
または、できます、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
私はpython開発者ではありませんが、どうしてこのようなことをしないのか疑問に思います。
class Product(object):
def __init__(self, version):
self.version = version
def function(self):
print('for version ' + self.version)
このためにデコレータを使用できます
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 '