'modül alma işlevinden' modül içe aktarma 'vs.


143

Her zaman bu yöntemi kullanıyorum:

from sys import argv

ve argvsadece argv ile kullanın . Ancak bunu kullanmanın bir kuralı var:

import sys

ve argv tarafından sys.argv

İkinci yöntem kodu kendi kendine belgelendiriyor ve ben (gerçekten) buna uyuyorum. Ama ilk yöntemi tercih etmemin nedeni hızlı çünkü tüm modülü içe aktarmak yerine sadece gerekli olan fonksiyonu alıyoruz (ki bu python'un bunları almak için zaman harcayacağı daha işe yaramaz fonksiyonları içerir). Sadece argv'a ihtiyacım olduğunu ve sys'deki diğer tüm fonksiyonların bana faydasız olduğuna dikkat edin.

Yani benim sorularım. İlk yöntem gerçekten komut dosyasını hızlı yapar mı? En çok hangi yöntem tercih edilir? Neden?



Yanıtlar:


175

Modülün içe aktarılması hiçbir şeyi boşa harcamaz ; modül her zaman tam olarak içe aktarılır ( sys.modulesharitaya çıkar), bu yüzden kullanıp kullanmadığınız import sysveya from sys import argvhiç şans tanımadığınızdan emin olun .

İki ifade arasındaki tek fark, hangi adın bağlı olduğu; import sysadı sys, modüle bağlar (so sys-> sys.modules['sys']), modülün içindeki özniteliğe doğrudan bakacak şekilde from sys import argvfarklı bir ad bağlar argv(so argv-> sys.modules['sys'].argv). sysModülden başka bir şey kullansanız da kullanmasanız da modülün geri kalanı hala orada.

İki yaklaşım arasında da performans farkı yoktur. Evet, sys.argviki şeye bakmak zorunda; sysglobal ad alanınıza bakmak zorundadır (modülü bulur), sonra niteliği aramak zorundadır argv. Ve evet, from sys import argvniteliği doğrudan aradığınız için, niteliği aramayı atlayabilirsiniz. Ancak importifadenin hala bu işi yapması gerekir, içe aktarırken aynı özelliği arar ve yalnızca bir argv kez kullanmanız gerekir . Eğer argvbir döngüde binlerce kez kullanmak zorunda kalsaydınız, belki de bir fark yaratabilirdi, ancak bu özel durumda gerçekten yapmıyordu.

Biri veya diğeri arasındaki seçim, bunun yerine kodlama stiline dayanmalıdır .

Bir de büyük modül, kesinlikle kullanmayı tercih ediyorum import sys; Kodlama önemlidir ve sys.argvbüyük bir modülde bir yerde kullanmak, ne demek istediğinizi her argvzamankinden daha net bir şekilde ortaya koyar .

Kullanmak tek yer ise argvbir olduğunu '__main__'bir aramaya bloğu main()kullanmak elbette, işlevini from sys import argvBu konuda daha mutlu hissetmiyorsanız:

if __name__ == '__main__':
    from sys import argv
    main(argv)

Hala import sysorada kendim kullanırdım . Her şey eşit olmak (ve tam olarak performans ve yazı yazmak için kullanılan karakter sayısı bakımından ), bu benim için gözüm daha kolay.

Tamamen başka bir şey ithal ediyorsanız , o zaman belki performans devreye girer. Fakat sadece bir modülde belirli bir ismi defalarca kullanıyorsanız , örneğin kritik bir döngüde. Ancak daha sonra yerel bir ad oluşturmak (bir fonksiyon içinde) daha hızlı olacak:

 import somemodule

 def somefunction():
      localname = somemodule.somefunctionorother
      while test:
          # huge, critical loop
          foo = localname(bar)

1
Ayrıca, üst ambalajdaki bu alt paketlerden / modüllerden birinin bir özelliğini ortaya koyan alt paketlere veya modüllere sahip bir paketinizin olması durumu da vardır. Kullanmak , paket içinde mantıksal veya kavramsal gruplamalar varsa, ancak paket kullanıcıları için biraz daha uygun hale getirmek istiyorsanız, yararlı olabilecek yerine from...importyapmanıza olanak sağlar . ( Böyle bir şey yaparsa, inanıyorum.)package.attributepackage.subpackage_or_module.attributenumpy
JAB

Django'da from django.core.management.base import BaseCommand, daha iyi gibi şeyler olan tonlarca noktaya sahipsiniz ve başka herhangi bir şey (özellikle de import django) okunamayan kodlara yol açacaktır. Dolayısıyla bu cevabı sevdiğimde, sözleşmenin çıplak ithalatı ihlal ettiği bazı kütüphaneler (ve özellikle bazı çerçeveler) olduğunu düşünüyorum. Her zaman olduğu gibi, belirli bir durumda neyin en iyisi olduğuna ilişkin kararınızı kullanın. Ancak, açık taraftaki hatalar (diğer bir deyişle, çoğunlukla katılıyorum).
nöronet

1
@JAB: Hala kullanabilirsiniz import ... asfarklı bir ad paketi bulmak için: import package.subpackage_or_module as shortname. from parent import subaslında, aynı şeyi yapar.
Martijn Pieters,

43

Kullanarak lehine iki nedeni vardır import moduleziyade from module import function.

İlk olarak ad alanı. Bir işlevi global isim alanına almak isim çarpışmalarını tehlikeye atar.

İkincisi, standart modüller için geçerli değildir, ancak özellikle geliştirme sırasında sizin için önemli olan modüllerdir. reload()Bir modül için seçenek bu . Bunu düşün:

from module import func
...
reload(module)
# func still points to the old code

Diğer yandan

import module
...
reload(module)
# module.func points to the new code

Hız gelince ...

tüm modülü içe aktarmak yerine yalnızca gerekli olan işlevi alıyoruz (bu, python'un içe aktarılması için zaman harcayacak daha işe yaramaz işlevler içerir)

Bir modül alır veya bir modülden bir fonksiyon alırsanız, Python tüm modülü ayrıştırır. Her iki şekilde de modül içe aktarılır. "Bir işlevi içe aktarmak", işlevi bir ada bağlamaktan başka bir şey değildir. Aslında import moduletercüman için daha az iş from module import func.


6
yeniden yükle () Python 2'de bir yerleşikti; bu artık Python 3 için geçerli değil.
André

Dairesel ithalat bağımlılıkları ile ilgisi olduğunu düşündüm?
ADP

18

from importOkunabilirliği arttırdığı zaman s kullanıyorum . Örneğin, tercih ediyorum (noktalı virgül yalnızca burada yer kazanmak için):

from collections import defaultdict
from foomodule import FooBar, FooBaz
from twisted.internet.protocol import Factory
defaultdict(); FooBar(); FooBaz(); Factory()

onun yerine:

import collections
import foomodule
import twisted.internet.protocol
collections.defaultdict(); foomodule.FooBar(); foomodule.FooBaz()
twisted.internet.protocol.Factory()

İkincisi, benim için okuması (ve yazması) daha zordur çünkü çok fazla gereksiz bilgi içermektedir. Ayrıca, bir modülün hangi bölümlerini kullandığımı önceden bilmek önemlidir.

importBir modülden çok sayıda kısa ad kullanıyorsam normal s'i tercih ederim :

import sys
sys.argv; sys.stderr; sys.exit()

Veya bir ad, ad alanının dışında bir anlam ifade etmeyecek kadar genelse:

import json
json.loads(foo)

from json import loads
loads(foo)  # potentially confusing

Bu benim en sevdiğim cevap. “Açık, örtük olmaktan iyidir” bazen okunabilirlik, basitlik ve DRY ile çakışıyor. Özellikle Django gibi bir çerçeve kullanırken.
nöronet

18

Benim düşünceme göre düzenli kullanarak importokunabilirliği artırır. Python kodunu incelerken, verilen işlevin veya sınıfın kullanıldığı yerin neresinden geldiğini görmek hoşuma gider. Bu bilgiyi almak için beni modülün üstüne kaydırmamdan kurtarıyor.

Uzun modül isimleri için sadece asanahtar kelimeyi kullanıyorum ve onlara kısa takma adlar verdim :

import collections as col
import foomodule as foo
import twisted.internet.protocol as twip

my_dict = col.defaultdict()
foo.FooBar()
twip_fac = twip.Factory()

Bir istisna from module import somethingolarak, __future__modülle uğraşırken her zaman gösterimi kullanıyorum . Python 2'de tüm dizelerin varsayılan olarak unicode olmasını istediğinizde başka bir yolla yapamazsınız, örn.

from __future__ import unicode_literals
from __future__ import print_function

Amin! "import as", kazanan bir kombinasyondur :-)
paj28

4

Her ne kadar import sysve from sys import agrvhem bütün ithal sysmodülü, ikincisi kullanır böylece sadece bağlayıcı isim argvmodül kodunun geri kalanı erişilebilir.

Bazı insanlar için bu tercih edilen tarz olacaktır çünkü yalnızca açıkça belirttiğiniz işleve erişebilir.

Ancak, potansiyel isim çatışmaları ortaya çıkarmaktadır. Ya adında başka bir modül varsa argv? Ayrıca, işlevi açıkça içe aktarabilir ve yeniden adlandırabilirsiniz. from sys import argv as sys_argvBu, açık içe aktarmayı karşılayan ve ad alanı çakışmaları verme olasılığı daha düşük olan bir kuraldır.


2
Peki, if sys_argv:daha iyi nasıl olabilir if sys.argv:? İkinci ifadenin ne anlama geldiğini biliyorum, ilk biçimin tuhaf ithalatı izlemeden ne anlama geldiğini bilmiyorum.
msn

1

Geçenlerde bu soruyu kendime sordum. Farklı yöntemleri zamanladım.

kütüphane ister

def r():
    import requests
    return 'hello'
timeit r() # output: 1000000 loops, best of 3: 1.55 µs per loop

def rg():
    from requests import get
    return 'hello'
timeit rg() # output: 100000 loops, best of 3: 2.53 µs per loop

güzel çorba kütüphane

def bs():
    import bs4
    return 'hello' 
timeit bs() # output: 1000000 loops, best of 3: 1.53 µs per loop

def be():
    from bs4 import BeautifulSoup
    return 'hello'
timeit be() # output: 100000 loops, best of 3: 2.59 µs per loop

json kütüphanesi

def js():
    import json
    return 'hello'
timeit js() # output: 1000000 loops, best of 3: 1.53 µs per loop

def jl():
    from json import loads
    return 'hello'
timeit jl() # output: 100000 loops, best of 3: 2.56 µs per loop

sys kütüphanesi

def s():
    import sys
    return 'hello'
timeit s() # output: 1000000 loops, best of 3: 1.55 µs per loop

def ar():
    from sys import argv
    return 'hello'
timeit ar() # output: 100000 loops, best of 3: 2.87 µs per loop

O geliyor bana orada performansında çok az fark var.


Bir özellik araması ekliyorsunuz. Doğru bir şekilde karşılaştırmak import moduleiçin from module import name, bu adı aramayı duruma ekleimport module . Örneğin satırı ekleyin sys.argviçin aryapılan çalışmalar olduğu için, hala bir fark var olacaktır, vb testte biraz farklı bayt kodu üretilir ve farklı codepaths yürütür gibi farklı.
Martijn Pieters,

2
Cevabımdaki bu farkı doğrudan ele aldığımı unutmayın; kullanarak arasında bir fark var olacak import syso zaman kullanarak sys.argvbir döngü içinde zaman binlerce vs from sys import argvsonra sadece kullanma argv. Ama sen yapmazsın. Modülünüzün sadece bir kez gerçekleştirdiği şeyler için, zamanlamadaki mikroskobik farklılıkları değil, gerçekten okunabilirlik için optimize etmelisiniz.
Martijn Pieters,

1
Ahhhh! Ve bir şeye bulaştığımı sanıyordum! :) Ben sadece cevabınızı yağsız. Silahı atlattım galiba. Geveze olmak iyi geliyor.
tmthyjames

-1

Yayınlanan kod parçalarına bakmak, tüm modülleri içe aktarmak ve module.functionen azından standart modüller için hemen hemen standart. Bir istisna gibi görünüyordatetime

from datetime import datetime, timedelta

diyebilirsiniz bu yüzden datetime.now()ziyade datetime.datetime.now().

Performansla ilgili endişeleriniz varsa, her zaman söyleyebilirsiniz (örneğin).

argv = sys.argv

ve daha sonra modül arama zaten yapıldığı için kritik performans kodunuzu yapın. Bununla birlikte, bu işlev / yöntemlerle çalışsa da, çoğu IDE'nin kafası karışır ve bir değişkene atandığında işlev için bir kaynak bağlantısı / imzası göstermez.


-2

Ben sadece eklemek isterim ki böyle bir şey yaparsanız

from math import sin

(veya başka bir dahili kütüphane gibi sysya posix), sonra sinyapmanız yani sizin modülünde (belgelerinde dahil edilecek >>> help(mymodule)veya $ pydoc3 mymoduleBunu önlemek için, ithal kullanarak.:

import math
from math import sin as _sin

Not: Yerleşik bir kütüphane, C kodundan derlenen ve Python'a dahil olan bir kütüphanedir. argparse, osve ioyerleşik paketler değil

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.